package ru.usu.gv.utils.imports.dynamic;

import ru.usu.gv.gui.layout.dynamic.DynamicLayoutUtilities;
import ru.usu.gv.utils.CommonUtilities;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author spupyrev
 * 09.12.2009
 */
public abstract class BaseData
{
	protected static final String BASE_PATH = "E:\\USU\\DynamicVis\\";
	public static int DAY = 24 * 60 * 60;

	protected static class Message
	{
		private int from;
		private int to;
		private int time;

		public Message(int time, int from, int to)
		{
			this.from = from;
			this.to = to;
			this.time = time;
		}
	}

	private List<Message> trace;
	private Map<Integer, String> names;
	private Map<String, String> genders;

	public BaseData()
	{
		try
		{
			readTrace();
			readNames();
			readGenders();
			readSpanners();
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

	protected abstract String getTracePath();

	protected abstract String getNamesPath();

	protected abstract String getGenderPath();

	public abstract int getStartTime();

	protected abstract int getEndTime();

	private void readTrace() throws IOException
	{
		trace = new ArrayList();
		FileInputStream file = new FileInputStream(getTracePath());

		String s;
		BufferedReader is = new BufferedReader(new InputStreamReader(file, "cp1251"));
		while ((s = is.readLine()) != null)
		{
			String[] tmp = s.split("[@\\-]");
			if (tmp.length != 3)
				continue;

			trace.add(new Message(Integer.parseInt(tmp[0]), Integer.parseInt(tmp[1]), Integer.parseInt(tmp[2])));
		}
		is.close();
		System.out.println("Read " + trace.size() + " trace elements");
	}

	private void readNames() throws IOException
	{
		names = new HashMap();
		FileInputStream file = new FileInputStream(getNamesPath());

		String s;
		BufferedReader is = new BufferedReader(new InputStreamReader(file, "cp1251"));
		while ((s = is.readLine()) != null)
		{
			String[] tmp = s.split(";");
			if (tmp.length != 2)
				continue;

			names.put(Integer.parseInt(tmp[1]), tmp[0]);
		}
		is.close();
		System.out.println("Read " + names.size() + " names");
	}

	private void readGenders() throws IOException
	{
		genders = new HashMap();
		FileInputStream file = new FileInputStream(getGenderPath());

		String s;
		BufferedReader is = new BufferedReader(new InputStreamReader(file, "cp1251"));
		while ((s = is.readLine()) != null)
		{
			String[] tmp = s.split(";");
			if (tmp.length != 2)
				continue;

			genders.put(tmp[0], tmp[1]);
		}
		is.close();
		System.out.println("Read " + genders.size() + " genders");
	}

	protected abstract void readSpanners() throws IOException;

	protected List<Message> filterMessages(List<Message> messages, int fromTime, int toTime)
	{
		List<Message> result = new ArrayList();
		for (Message message : messages)
			if (fromTime <= message.time && message.time < toTime)
				result.add(message);

		return result;

	}

	public List<Message> getMessages(int fromTime, int toTime)
	{
		return filterMessages(trace, fromTime, toTime);
	}

	public Map<Integer, Map<Integer, Double>> getEdges(int beginDay, int endDay)
	{
		return getEdges(beginDay, endDay, 1);
	}

	public Map<Integer, Map<Integer, Double>> getEdges(int beginDay, int endDay, int minCount)
	{
		List<Message> messages = filterMessages(trace, getStartTime() + beginDay * DAY, getStartTime() + endDay * DAY);
		Map<Integer, Map<Integer, Double>> result = new HashMap();
		for (Message message : messages)
		{
			if (!result.containsKey(message.from))
				result.put(message.from, new HashMap());

			if (!result.containsKey(message.to))
				result.put(message.to, new HashMap());

			CommonUtilities.incrementMap(result.get(message.from), message.to);
			CommonUtilities.incrementMap(result.get(message.to), message.from);
		}

		Map<Integer, Map<Integer, Double>> result2 = new HashMap();
		for (int i : result.keySet())
			for (int j : result.get(i).keySet())
				if (result.get(i).get(j) >= minCount)
					DynamicLayoutUtilities.addEdge(result2, i, j, result.get(i).get(j));
		
		return result2;
	}

	protected Map<Integer, Set<Integer>> getSpannerEdges(List<Message> allMessages, int day)
	{
		List<Message> messages = filterMessages(allMessages, getStartTime() + (day + 1) * DAY, getStartTime() + (day + 2) * DAY);
		Map<Integer, Set<Integer>> result = new HashMap();
		for (Message message : messages)
		{
			if (!result.containsKey(message.from))
				result.put(message.from, new HashSet());

			if (!result.containsKey(message.to))
				result.put(message.to, new HashSet());

			result.get(message.from).add(message.to);
			result.get(message.to).add(message.from);
		}

		return result;
	}

	public String getGender(int id)
	{
		String name = getName(id);
		if (!genders.containsKey(name))
			return "";
		return genders.get(name);
	}

	public String getName(int id)
	{
		if (!names.containsKey(id))
			return "" + id;
		return names.get(id);
	}

	public Map<Integer, Map<Integer, Double>> getWeightedEdges(Map<Integer, Set<Integer>> edges)
	{
		Map<Integer, Map<Integer, Double>> res = new HashMap();
		for (int id : edges.keySet())
		{
			res.put(id, new HashMap());
			for (int neig : edges.get(id))
				res.get(id).put(neig, 1.0);
		}
		return res;
	}

}
